/**
 * Copyright 2009-2010 - YangJiandong(chunquedong)
 * 
 * This file is part of ChunMap project
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE(Version >=3)
 * 你可以自由复制、传播本项目的下载包文件，但必须保持其完整性。
 * 我们不用对使用中的风险及由此造成的损失承担任何责任。
 * 详细情况请见《ChunMap许可协议》。

 * 想了解更多有关ChunMap的信息，请访问http://code.google.com/p/chunmap/
 */
package chunmap.data.provider.shp;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

import chunmap.model.elem.Envelope;
import chunmap.model.geom.GeoPoint;
import chunmap.model.geom.Geometry;
import chunmap.model.geom.GeometryType;

/**
 * @author chunquedong
 * 
 */
public class ShapefileReader {
	private String path;
	private String name;
	private RandomAccessFile shaperf;
	private RandomAccessFile indexrf;
	private GeometryType geometryType;
	private int shapefileType;
	private long shapeCount;
	private int version;
	private Envelope envelop;
	private final ShapefileReaderHelper helper = new ShapefileReaderHelper();

	public ShapefileReader(String path) {
		setPath(path);
		open();
		readHeader();
	}

	private void setPath(String apath) {

		File file = new File(apath);
		this.name = file.getName();

		this.path = apath.substring(0, apath.lastIndexOf("."));
	}

	private void open() {
		try {
			shaperf = new RandomAccessFile(path + ".shp", "r");
			indexrf = new RandomAccessFile(path + ".shx", "r");
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	public void close() {
		try {
			indexrf.close();
			shaperf.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	private void readHeader() {
		try {
			// 文件编号
			indexrf.seek(0);
			int ii = indexrf.readInt();
			if (ii != 9994)
				throw new IOException("bad file");
			// 文件长度
			indexrf.seek(24);
			int fileLength = 2 * indexrf.readInt();// 16位算一个
			// 图形个数
			shapeCount = (fileLength - 100) / 8;// 100bytes头文件。偏移4bytes，长度4bytes，没条记录共占8bytes。
			// 格式版本
			version = Integer.reverseBytes(indexrf.readInt());
			// 图类型
			shapefileType = Integer.reverseBytes(indexrf.readInt());
			// 边框盒子
			geometryType = ShapefileType.getShapeType(shapefileType);

			envelop = helper.readEnvelop(indexrf);

		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		// _envelop.MinPoint.Z = _binaryReader_Index.ReadDouble();
		// _envelop.MaxPoint.Z = _binaryReader_Index.ReadDouble();
		// _envelop.MinPoint.Coordinate.M = _binaryReader_Index.ReadDouble();
		// _envelop.MaxPoint.Coordinate.M = _binaryReader_Index.ReadDouble();
	}

	public Geometry getGeometry(long id) throws IOException {
		int index = getIndex(id) + 8;// 加8表示跳过记录头信息，包括记录号和记录长度。
		shaperf.seek(index);
		int type = Integer.reverseBytes(shaperf.readInt());
		Geometry geometry;

		switch (type) {
		case ShapefileType.Null:
			return null;

		case ShapefileType.Point:
			geometry = new GeoPoint(helper.readPoint(shaperf));
			break;

		case ShapefileType.Multipoint:
			geometry = helper.readMultiPoint(shaperf);
			break;

		case ShapefileType.PolyLine:
			geometry = helper.readMultiLine(shaperf);
			break;

		case ShapefileType.Polygon:
			geometry = helper.readMultiPolygon(shaperf);
			break;

		// case ShapefileType.PointM:
		// geometry = helper.readPointM(shaperf);
		// break;

		// case ShapefileType.MultiPointM:
		// geometry = helper.readMultiPointM(shaperf);
		// break;

		// case ShapefileType.PolyLineM:
		// geometry = helper.readMultiLineM(shaperf);
		// break;

		// case ShapefileType.PolygonM:
		// geometry = helper.readMultiPolygonM(shaperf);
		// break;

		// case ShapefileType.PointZ:
		// geometry = helper.readPointZ(shaperf);
		// break;

		// case ShapefileType.MultiPointZ:
		// geometry = helper.readMultiPointZ(shaperf);
		// break;

		// case ShapefileType.PolyLineZ:
		// geometry = helper.readMultiPolygonZ(shaperf);
		// break;
		//
		// case ShapefileType.PolygonZ:
		// geometry = helper.readMultiLineZ(shaperf);
		// break;

		default:
			throw new UnsupportedOperationException(
					"this ShapefileType is unsupported");
		}
		//geometry.setId(id + "");
		return geometry;
	}

	// 从索引文件查到偏移量
	public int getIndex(long id) throws IOException {
		indexrf.seek(id * 8 + 100);
		return 2 * indexrf.readInt();// 16位算一个

	}

	public Envelope getShapeEnvelop(long id) throws IOException {
		int index = getIndex(id) + 8;// 加8表示跳过记录头信息，包括记录号和记录长度。
		shaperf.seek(index);
		int type = Integer.reverseBytes(shaperf.readInt());

		Envelope elp;
		if (type == ShapefileType.Null)
			return new Envelope();
		else if (type == ShapefileType.Point || type == ShapefileType.PointM
				|| type == ShapefileType.PointZ) {
			elp = new GeoPoint(helper.readPoint(shaperf)).getEnvelop();
		} else {
			elp = helper.readEnvelop(shaperf);
		}

		return elp;
	}

	public String getPath() {
		return path;
	}

	public String getName() {
		return name;
	}

	public GeometryType getGeometryType() {
		return geometryType;
	}

	public int getShapefileType() {
		return shapefileType;
	}

	public long getShapeCount() {
		return shapeCount;
	}

	public int getVersion() {
		return version;
	}

	public Envelope getEnvelop() {
		return envelop;
	}
}
